home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
HENSA
/
MISC
/
SHELL.ARC
/
Shell
/
Sources
/
c
/
TextRect
< prev
next >
Wrap
Text File
|
1994-08-29
|
10KB
|
412 lines
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "DeskLib:WimpSWIs.h"
#include "DeskLib:Error.h"
#include "Shell.Shell.h"
#include "Shell.Extra.h"
#include "Shell.SafeAlloc.h"
#include "Shell.TextRect.h"
#define Shell_TEXT_INCREMENT 4096
/* Text is stored in a malloc-ed block which is a multiple of this size */
/* so as to avoid repeadly realloc-ing */
typedef struct { /* this is used to record a reference point in some */
int line; /* text. 'offset' is the position in text of the first */
int offset; /* chr of line-number 'line'. */
}
Shell_textref;
typedef struct {
char *text; /* The text. */
int datasize, /* Length of text *excluding* the '\0'. */
maxdatasize; /* Space currently rserved for text (excl '\0').*/
int numlines, /* The number of lines in the text... */
maxlinelen; /* Used to check whether window is wide enough. */
Shell_textref top, bottom, last; /* 'top' is for top visible line in the window. */
} /* 'bottom' is for the last visible line. */
Shell_textrectblock; /* 'last' is for the last line in the text. */
/* 'top' and 'bottom' are updated each time any */
/* part of the text is re-drawn, and are set to */
/* first and last line of the redrawn text. */
static int Shell_TextRectFindLineNumber( const Shell_textrectblock *info, int line)
/* This function returns the position of the first charater of line number 'line' */
/* in info->text. It finds which reference point is nearest to line number 'line, */
/* then counts forward or backwards, counting line-feeds until is reaches the start of */
/* line-number 'line'. */
/* It all looks a bit long-winded, partly 'cos I've tried to make it run fast. */
/* It should really be in assembler for speed, but I don't know nearly enough for that. */
{
Shell_textref nearest;
int step;
if ( line >= info->numlines) return -1;
if ( line == 0) return 0;
/* find reference line that is closest to line */
if ( line <= info->top.line) {
if ( (line-info->top.line-line) < line-0 ) {
nearest = info->top;
step = -1;
}
else {
nearest.line=0;
nearest.offset =0;
step = +1;
}
}
else if ( line <= info->bottom.line) {
if ((info->bottom.line-line) < (line-info->top.line)) {
nearest = info->bottom;
step = -1;
}
else {
nearest = info->top;
step = +1;
}
}
else {
if ((info->last.line-line) < (line-info->bottom.line)) {
nearest = info->last;
step = -1;
}
else {
nearest = info->bottom;
step = +1;
}
}
/* now step along from the reference line, counting LF's until we have reached the line... */
if ( step > 0) {
for ( ; nearest.line != line; nearest.offset++) {
if ( info->text[nearest.offset]=='\n') nearest.line++;
}
}
else {
for ( nearest.offset -= 2; nearest.line != line; nearest.offset--) {
if ( info->text[nearest.offset]=='\n') nearest.line--;
}
nearest.offset+=2;
}
/* nearest.offset is position in info->text of the first chr of line-number 'line'.*/
/* Just check here that this position is not outside the range of the text, to */
/* prevent subsequent overwriting of memory. */
if ( nearest.offset < 0 || nearest.offset > info->datasize)
Error_ReportFatal( 1, Error_PLACE "Error in Shell_TextRectFindLineNumber");
return nearest.offset;
}
static BOOL Shell_TextRectSaver( char *filename, Shell_rectblock *r)
{
FILE *f;
Shell_textrectblock *textrectblock = (Shell_textrectblock *) r->reference;
f = fopen( filename, "w");
if ( !f) return FALSE;
fprintf( f, textrectblock->text);
fclose(f);
return TRUE;
}
#define Min( a, b) ( (a) < (b) ) ? (a) : (b)
static int Shell_TextRectRAMSaver(
task_handle sourcetask,
Shell_rectblock *r,
task_handle desttask,
void *destbuffer,
unsigned int buffersize,
int progress
)
{
Shell_textrectblock *textrectblock = (Shell_textrectblock *) r->reference;
int n;
n = Min( textrectblock->datasize - progress, buffersize);
/* The length of the text in the rect is ...->datasize. This excludes */
/* the '\0', which looks a bit funny if included into a text editor */
Wimp_TransferBlock(
sourcetask, textrectblock->text + progress,
desttask, destbuffer,
n
);
return n;
}
static void Shell_TextRectRedrawer(
Shell_convertpoint convert,
wimp_point rectsize,
void *reference,
const wimp_rect *redrawrect
)
{ Shell_textrectblock *info = reference;
wimp_rect rect = *redrawrect;
int n;
char *c;
Shell_ConvertToSubTextRect2( &rect, rectsize);
n = Shell_TextRectFindLineNumber( info, rect.min.y);
if ( n!= -1) {
c = &info->text[n];
info->top.line = rect.min.y; /* Update top reference point. */
info->top.offset = n; /* This will be useful in subsequent redraws */
if ( rect.max.y > info->numlines) rect.max.y = info->numlines;
{ int y;
char *cc;
for ( y=rect.min.y, cc=c; y<=rect.max.y; y++, c=cc+1) {
/* print line number y. Put a '\0' temporarily at end of line */
cc = strchr( c, '\n'); if (cc) *cc=0;
Shell_PrintString(
c, 0, rectsize.y - y*Shell_TEXTYSIZE, convert
);
if (cc) *cc = '\n';
else break;
}
info->bottom.line = y;
info->bottom.offset = ( c - info->text);
}
}
return;
}
Shell_rectblock *Shell_AddTextRect( Shell_windblock *w, int x, int y, int forecol, int backcol)
{
Shell_textrectblock *info = Shell_SafeMalloc( sizeof( Shell_textrectblock));
Shell_rectblock *r;
info->text = Shell_SafeMalloc( 1+Shell_TEXT_INCREMENT); info->text[0] = 0;
info->maxdatasize = Shell_TEXT_INCREMENT;
info->datasize = 0;
info->maxlinelen = 0;
info->numlines = 1;
info->last.line = 0;
info->top.line = 0;
info->bottom.line = 0;
info->last.offset = 0;
info->top.offset = 0;
info->bottom.offset = 0;
r = Shell_AddRectangle2(
w, x, y-Shell_TEXTYSIZE, x+Shell_TEXTXSIZE, y,
Shell_TextRectRedrawer, info
);
Shell_MakeRectIcon( r, forecol, backcol, "R2");
r->saver = Shell_TextRectSaver;
r->ramsaver = Shell_TextRectRAMSaver;
r->size = 0;
return r;
}
Shell_rectblock *Shell_defaulttextrectblock = NULL; /* Not opened yet. */
void Shell_TextRectPrint( Shell_rectblock *rect, const char *text)
{ int extraneeded;
int lastLF, numlines, size;
Shell_textrectblock *info;
/* Check whether the rect is Shell_'s default textrect */
/* and open a window + textrect if one isn't opened already */
if ( rect == Shell_defaulttextrect) rect = Shell_defaulttextrectblock;
/* Plot to the default text-rect window. */
if ( rect == NULL) {
rect = Shell_defaulttextrectblock =
Shell_AddTextRect(
Shell_OpenGFXWindow(),
0,
0,
colour_BLACK,
colour_TRANSPARENT
);
}
/* Have to open a new window, and add a textrect */
if ( text[0]==0) return;
/* Can now do the actual text-printing... */
/* This involves adding 'text' to the end of the existing text. */
/* We have to calculate how many lines are added, whether the */
/* max-linelength has increased, etc. */
info = (Shell_textrectblock *) rect->reference;
/* Count number of linefeeds in the new text, also find length, and */
/* max line-length. Could do this with str* functions, but this will be */
/* quicker as it only loops through the text once. */
{
char *c = (char *) text;
int linelen;
size = 0;
numlines = 0;
lastLF = -(int) ( info->datasize - info->last.offset) - 1;
/* last.offset is ptr to chr *after* the last '\n', so this makes lastLF */
/* be the position of the last '\n' */
for ( ; ; c++, size++) {
if ( *c == '\n' || ( !*c) ) {
linelen = (int) ( c-text) - lastLF - 1;
if ( linelen > info->maxlinelen) info->maxlinelen = linelen;
if ( *c) {
lastLF = c-text;
numlines++;
}
}
if (!*c) break;
}
}
extraneeded = info->datasize + size - info->maxdatasize;
if ( extraneeded > Shell_TEXT_INCREMENT) {
info->text = Shell_SafeRealloc( info->text, info->datasize+size+1);
info->maxdatasize = info->datasize + size;
}
else if ( extraneeded > 0) {
info->text = Shell_SafeRealloc( info->text, info->maxdatasize+Shell_TEXT_INCREMENT+1);
info->maxdatasize += Shell_TEXT_INCREMENT;
}
strcpy( &info->text[ info->datasize], text);
if ( lastLF>=0) {
info->last.offset = lastLF + info->datasize+1; /* datasize is still old value */
/* ptr is to the chr AFTER the LF */
info->last.line += numlines;
info->numlines += numlines;
}
info->datasize += size;
rect->size = info->datasize;
{
int oldrectminy = rect->rect.min.y;
BOOL yscrollbottom = Shell_CheckYScrollIsBottom( rect->window);
wimp_rect newrect; /* This is the new rect at the bottom. */
rect->rect.max.x = rect->rect.min.x + Shell_TEXTXSIZE * info->maxlinelen;
rect->rect.min.y = rect->rect.max.y - Shell_TEXTYSIZE * info->numlines;
Shell_ResizeIconRect( rect);
newrect = rect->rect;
newrect.max.y = oldrectminy + Shell_TEXTYSIZE;
/*Shell_CheckWindSizeAndRedraw( rect->window, &rect->icon.workarearect);*/
Shell_CheckWindSizeAndRedraw( rect->window, &newrect);
if ( yscrollbottom) Shell_MoveYScrollToBottom( rect->window);
}
}
void Shell_TextRectPrintf( Shell_rectblock *rectblock, const char *fmt, ...)
{ va_list args;
int len;
len = strlen( fmt);
if ( len > Shell_stringMAX) {
Error_Report( 0,
"Format string length %i is too long for Shell_TextRectPrintf. Max length is %i",
len, Shell_stringMAX
);
Shell_TextRectPrint( rectblock, "*** string too long for Shell_TextRectPrintf ***\n");
return;
}
va_start( args, fmt);
vsprintf( Shell_string, fmt, args);
va_end( args);
len = strlen( Shell_string);
if ( len > Shell_stringMAX) {
Error_Report( 0,
"Expanded string length %i is too long (max is %i). Shell must exit.",
len, Shell_stringMAX
);
exit( 1);
}
Shell_TextRectPrint( rectblock, Shell_string);
}